package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.common.dto.PageDTO;
import com.leyou.common.utils.JsonUtils;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.service.*;
import org.bouncycastle.asn1.esf.SPuri;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SpuDetailService detailService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpecParamService paramService;


    @Override
    public PageDTO<SpuDTO> pageQuery(Integer page, Integer rows, Long id, Long bid, Long cid, Boolean saleable) {

        Page<Spu> spuPage = new Page<>(page, rows);
        page(spuPage, new QueryWrapper<Spu>()
                .eq(id != null, "id", id)
                .eq(null != bid, "brand_id", bid)
                .eq(null != cid, "cid3", cid)
                .eq(null != saleable, "saleable", saleable));

        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(spuPage.getRecords());

        spuDTOS.forEach(spuDTO -> {
            //根据品牌id查询对应的品牌对象，获取其name
            spuDTO.setBrandName(getBrandName(spuDTO.getBrandId()));
            String names = getCategoryName(spuDTO.getCategoryIds());


            //TODO 考虑优化问题，分类及品牌查询时候缓存问题
            spuDTO.setCategoryName(names);
        });

        return new PageDTO<>(spuPage.getTotal(), spuPage.getPages(), spuDTOS);
    }

    private String getCategoryName(List<Long> cids) {
        //根据分类id的集合查询对应的分类的集合
        return this.categoryService
                .queryCategoryByIds(cids)
                .stream()
                .map(CategoryDTO::getName)
                .collect(Collectors.joining("/"));
    }

    private String getBrandName(Long brandId) {
        return this.brandService.getById(brandId).getName();
    }

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    @Transactional
    public void modifySaleable(Long spuId, Boolean saleable) {
        //todo 修改spu

        Spu spu = new Spu();
        spu.setId(spuId);

        spu.setSaleable(saleable);

        //update tb_spu set saleable = true where id = 2
        updateById(spu);

        //todo 修改sku

        Sku sku = new Sku();
        sku.setSaleable(saleable);

        //update tb_sku set saleable = true where spu_id = 2
        this.skuService.update(sku, new QueryWrapper<Sku>().eq("spu_id", spuId));

        String key = saleable ? "item.up" : "item.down";
        //生产者发送消息
        this.amqpTemplate.convertAndSend("shangPin",key,spuId);
    }

    @Override
    @Transactional
    public void saveGoods(SpuDTO spuDTO) {
        Spu spu = spuDTO.toEntity(Spu.class);

        //保存spu并回显主键
        if (this.save(spu)) {

            SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);
            spuDetail.setSpuId(spu.getId());
            this.detailService.save(spuDetail);

            //获得skuDTO的集合，把每个skuDTO转为sku并赋值spuId
            List<Sku> skus = spuDTO.getSkus()
                    .stream()
                    .map(skuDto -> {
                        Sku sku = skuDto.toEntity(Sku.class);
                        sku.setSpuId(spu.getId());
                        sku.setSaleable(true);//默认新增即上架
                        return sku;
                    }).collect(Collectors.toList());

            this.skuService.saveBatch(skus);

        }
    }

    @Override
    public SpuDTO querySpuById(Long id) {

        //根据spuId查询spu转为SpuDTO
        SpuDTO spuDTO = new SpuDTO(getById(id));

        //根据brandId以及categoryIds查询对应的分类及品牌名称
        spuDTO.setCategoryName(getCategoryName(spuDTO.getCategoryIds()));
        spuDTO.setBrandName(getBrandName(spuDTO.getBrandId()));

        spuDTO.setSpuDetail(new SpuDetailDTO(this.detailService.getById(spuDTO.getId())));

        //给spu赋值skus，select * from tb_sku where spu_id = #{spuId}
        spuDTO.setSkus(
                SkuDTO
                        .convertEntityList(
                                this.skuService
                                        .query()
                                        .eq("spu_id", spuDTO.getId())
                                        .list()));

        return spuDTO;
    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {

        Long spuId = spuDTO.getId();

        Long spuDetailId = spuDTO.getSpuDetail().getSpuId();

        List<SkuDTO> skuDTOs = spuDTO.getSkus();

        //判断修改逻辑要不要执行
        if (null == spuId && null == spuDetailId && (null == skuDTOs || 0 == skuDTOs.size())) {
            return;
        }

        //改谁，

        //有spuId，说明spu要改

        if (null != spuId) {
            Spu spu = spuDTO.toEntity(Spu.class);
            updateById(spu);
        }

        //如果有spuDetail，说明spuDetail要改

        if (null != spuDetailId) {
            SpuDetail spuDetail = spuDTO.getSpuDetail().toEntity(SpuDetail.class);

            this.detailService.updateById(spuDetail);
        }
        //如果skus数组有值说明sku要改
        if (null != skuDTOs && 0 != skuDTOs.size()) {
            //分组，

            //分组函数，分组的条件为skuDTO得到saleable属性的值，如果属性值为  true,false
            Map<Boolean, List<Sku>> skuMap = skuDTOs
                    .stream()
                    .map(skuDTO -> skuDTO.toEntity(Sku.class))
                    .collect(Collectors.groupingBy(sku -> {
                        return sku.getSaleable() == null;
                    }));

            //true的一组表示的为新增或者修改（新增和修改时不提交saleable所以值为null）
            this.skuService.saveOrUpdateBatch(skuMap.get(true));

            //为false的一组表示要删除
            this.skuService.removeByIds(skuMap.get(false).stream().map(Sku::getId).collect(Collectors.toList()));
        }
    }

    @Override
    public List<SpecParamDTO> queryParams(Long id, Boolean searching) {
        //获取分类，根据分类查询其规格参数,同时传入searching
        List<SpecParamDTO> specParamDTOS =
                this.paramService.queryParams(null, getById(id).getCid3(), searching);


        //获取规格属性的键值对，key为规格参数的id，value为对应的规格值，nativeRead，json粉碎机，什么类型都可以处理
        Map<Long, Object> specMap = JsonUtils.nativeRead(
                this.detailService.getById(id).getSpecification(),
                new TypeReference<Map<Long, Object>>() {
                });


        //循环给规格参数添加属性，value
        specParamDTOS.forEach(specParamDTO -> {
            specParamDTO.setValue(specMap.get(specParamDTO.getId()));
        });


        return specParamDTOS;
    }
}
